package common.model.response.base;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import common.config.exception.BaseErrorInfoInterface;
import common.config.exception.CustomException;
import common.config.http.HttpStatusEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.util.function.Consumer;

/**
 * 公共响应结果
 *
 * @author 米泽鹏
 * @since 2021-07-08 下午 7:17
 */
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Slf4j
public class Result<T> implements Serializable {

	/**
	 * 成功结果的状态码
	 */
	public static final Integer SUCCESS_CODE = HttpStatusEnum.SUCCESS.getCode();

	/**
	 * 成功结果的默认成功信息
	 */
	public static final String DEFAULT_SUCCESS_MESSAGE = HttpStatusEnum.SUCCESS.getMessage();

	/**
	 * 错误结果的默认状态码
	 */
	public static final Integer DEFAULT_ERROR_CODE = HttpStatusEnum.INTERNAL_SERVER_ERROR.getCode();

	/**
	 * 错误结果的默认错误信息
	 */
	public static final String DEFAULT_ERROR_MESSAGE = HttpStatusEnum.INTERNAL_SERVER_ERROR.getMessage();

	/**
	 * 响应代码
	 */
	private Integer code;

	/**
	 * 响应消息
	 */
	private String message;

	/**
	 * 响应数据
	 */
	private T data;

	/**
	 * 异常信息：Exception或Error
	 */
	private transient Throwable throwable;

	public Result(BaseErrorInfoInterface baseErrorInfoInterface) {
		this.code = baseErrorInfoInterface.getCode();
		this.message = baseErrorInfoInterface.getMessage();
	}

	/**
	 * 成功（含：状态码、描述）
	 */
	public static <T> Result<T> success() {
		Result<T> result = new Result<>();
		result.setCode(SUCCESS_CODE);
		result.setMessage(DEFAULT_SUCCESS_MESSAGE);
		return result;
	}

	/**
	 * 成功（含：状态码、描述、数据）
	 */
	public static <T> Result<T> success(String message, T data) {
		Result<T> result = new Result<>();
		result.setCode(SUCCESS_CODE);
		result.setMessage(message);
		result.setData(data);
		return result;
	}

	/**
	 * 成功（含：状态码、描述）
	 */
	public static <T> Result<T> successWithMessage(String message) {
		Result<T> result = new Result<>();
		result.setCode(SUCCESS_CODE);
		result.setMessage(message);
		return result;
	}

	/**
	 * 成功（含：状态码、描述、数据）
	 */
	public static <T> Result<T> successWithData(T data) {
		Result<T> result = new Result<>();
		result.setCode(SUCCESS_CODE);
		result.setMessage(DEFAULT_SUCCESS_MESSAGE);
		result.setData(data);
		return result;
	}

	/**
	 * 失败
	 */
	public static <T> Result<T> error() {
		Result<T> result = new Result<>();
		result.setCode(DEFAULT_ERROR_CODE);
		result.setMessage(DEFAULT_ERROR_MESSAGE);
		return result;
	}

	/**
	 * 失败（通过BaseErrorInfoInterface创建失败响应）
	 */
	public static <T> Result<T> error(BaseErrorInfoInterface baseErrorInfoInterface) {
		Result<T> result = new Result<>();
		result.setCode(baseErrorInfoInterface.getCode());
		result.setMessage(baseErrorInfoInterface.getMessage());
		return result;
	}

	/**
	 * 失败（含：错误码、描述）
	 */
	public static <T> Result<T> error(Integer code, String message) {
		Result<T> result = new Result<>();
		result.setCode(code);
		result.setMessage(message);
		return result;
	}

	/**
	 * 失败（含：错误码、描述）
	 */
	public static <T> Result<T> error(String message) {
		Result<T> result = new Result<>();
		result.setCode(DEFAULT_ERROR_CODE);
		result.setMessage(message);
		return result;
	}

	/**
	 * 失败（含：错误码、描述、异常信息）
	 */
	public static <T> Result<T> error(Integer code, Throwable throwable) {
		Result<T> result = new Result<>();
		result.setCode(code);
		result.setMessage(ExceptionUtil.getSimpleMessage(throwable));
		result.setThrowable(throwable);
		return result;
	}

	/**
	 * 失败（含：错误码、描述、异常信息）
	 */
	public static <T> Result<T> error(Throwable throwable) {
		Result<T> result = new Result<>();
		result.setCode(DEFAULT_ERROR_CODE);
		result.setMessage(ExceptionUtil.getSimpleMessage(throwable));
		result.setThrowable(throwable);
		return result;
	}

	public Integer getCode() {
		return ObjectUtil.defaultIfNull(code, DEFAULT_ERROR_CODE);
	}

	public String getMessage() {
		return StrUtil.blankToDefault(message, DEFAULT_ERROR_MESSAGE);
	}

	public boolean wasSuccessful() {
		return SUCCESS_CODE.equals(code);
	}

	public boolean wasFailed() {
		return !wasSuccessful();
	}

	public void throwExceptionIfFailed() {
		if (!wasSuccessful()) {
			if (throwable != null) {
				throw new CustomException(throwable);
			} else {
				throw new CustomException(getCode(), getMessage());
			}
		}
	}

	public void printLogIfFailed() {
		if (!wasSuccessful()) {
			if (throwable != null) {
				log.error(ExceptionUtil.getRootCauseMessage(throwable), throwable);
			} else {
				log.error("{}: {}", getCode(), getMessage());
			}
		}
	}

	public void wasSuccessfulAndThen(Consumer<Result<T>> consumer) {
		if (wasSuccessful()) {
			consumer.accept(this);
		} else {
			throw throwable == null ? new CustomException(getCode(), getMessage()) : new CustomException(throwable);
		}
	}

	public Result<T> wasFailedAndThen() {
		if (wasSuccessful()) {
			String detailMessage = String.format("断言错误：Result: %s 是成功的，却断言了失败", JSONUtil.toJsonPrettyStr(this));
			throw new CustomException(detailMessage);
		} else {
			return this;
		}
	}

	@Override
	public String toString() {
		return JSONUtil.toJsonPrettyStr(this);
	}

}
